package com.wbl.train.batch.controller;

import com.wbl.train.batch.req.CronJobReq;
import com.wbl.train.batch.resp.CronJobResp;
import com.wbl.train.common.exception.ApplicationException;
import com.wbl.train.common.result.R;
import com.wbl.train.common.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;



/**
 * Author: 王博纶
 * Date: 2024/2/8 16:54
 * FileName: JobController
 * Description: 定时任务的controller类
 */
@Slf4j
@RestController
@RequestMapping(value = "/admin/job")
public class JobController {

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    /**
     * 手动执行一次定时任务
     */
    @RequestMapping(value = "/run")
    public R<String> run(@RequestBody CronJobReq cronJobReq) throws SchedulerException {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        log.info("手动执行任务开始：{}, {}", jobClassName, jobGroupName);
        schedulerFactoryBean.getScheduler().triggerJob(JobKey.jobKey(jobClassName, jobGroupName));
        return R.ok("手动执行成功");
    }

    /**
     * 添加定时任务
     */
    @RequestMapping(value = "/add")
    public R<String> add(@RequestBody CronJobReq cronJobReq) throws ClassNotFoundException {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        String cronExpression = cronJobReq.getCronExpression();
        String description = cronJobReq.getDescription();
        log.info("创建定时任务开始：{}，{}，{}，{}", jobClassName, jobGroupName, cronExpression, description);
        try {
            // 通过SchedulerFactory获取一个调度器实例
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            // 启动调度器
            scheduler.start();
            // 构建job信息
            JobDetail jobDetail = JobBuilder
                    // 构建一个新的任务
                    .newJob((Class<? extends Job>) Class.forName(jobClassName))
                    // 设置任务的名称和分组
                    .withIdentity(jobClassName, jobGroupName)
                    // 开始构建
                    .build();
            // cron表达式调度构建器(即任务执行的时间)
            CronScheduleBuilder scheduleBuilder = null;
            try {
                scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            } catch (Exception e) {
                throw new ApplicationException(ResultCode.TEXT_PARSE_ERROR ,"文本解析异常");
            }
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger = TriggerBuilder
                    // 构建一个新的调度器trigger
                    .newTrigger()
                    // 任务的名称和分组
                    .withIdentity(jobClassName, jobGroupName)
                    // 任务的描述
                    .withDescription(description)
                    // 使用cron表达式设置执行的频率
                    .withSchedule(scheduleBuilder)
                    // 开始构建
                    .build();
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error("创建定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("创建定时任务结束");
        return R.ok("创建定时任务成功");
    }

    /**
     * 暂停定时任务
     */
    @RequestMapping(value = "/pause")
    public R<String> pause(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        log.info("暂停定时任务开始：{}，{}", jobClassName, jobGroupName);
        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            log.error("暂停定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("暂停定时任务结束");
        return R.ok("定时任务已暂停");
    }

    /**
     * 重启定时任务
     */
    @RequestMapping(value = "/resume")
    public R<String> resume(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        log.info("重启定时任务开始：{}，{}", jobClassName, jobGroupName);
        try {
            Scheduler sched = schedulerFactoryBean.getScheduler();
            sched.resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            log.error("重启定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("重启定时任务结束");
        return R.ok("定时任务重启成功");
    }

    /**
     * 重置定时任务
     */
    @RequestMapping(value = "/reschedule")
    public R<String> reschedule(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        String cronExpression = cronJobReq.getCronExpression();
        String description = cronJobReq.getDescription();
        log.info("更新定时任务开始：{}，{}，{}，{}", jobClassName, jobGroupName, cronExpression, description);
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
            CronTriggerImpl trigger1 = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
            trigger1.setStartTime(new Date()); // 重新设置开始时间
            CronTrigger trigger = trigger1;

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger
                    .getTriggerBuilder()
                    .withIdentity(triggerKey)
                    .withDescription(description)
                    .withSchedule(scheduleBuilder)
                    .build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            log.error("更新定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("更新定时任务结束");
        return R.ok("定时任务重置成功");
    }


    /**
     * 删除定时任务
     */
    @RequestMapping(value = "/delete")
    public R<String> delete(@RequestBody CronJobReq cronJobReq) {
        String jobClassName = cronJobReq.getName();
        String jobGroupName = cronJobReq.getGroup();
        log.info("删除定时任务开始：{}，{}", jobClassName, jobGroupName);
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
            scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
        } catch (SchedulerException e) {
            log.error("删除定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("删除定时任务结束");
        return R.ok("删除成功");
    }

    /**
     * 查询定时任务
     */
    @RequestMapping(value="/query")
    public R<List<CronJobResp>> query() {
        log.info("查看所有定时任务开始");
        List<CronJobResp> cronJobDtoList = new ArrayList<>();
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            for (String groupName : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {
                    CronJobResp cronJobResp = new CronJobResp();
                    cronJobResp.setName(jobKey.getName());
                    cronJobResp.setGroup(jobKey.getGroup());

                    //get job's trigger
                    List<Trigger> triggers = (List<Trigger>) scheduler.getTriggersOfJob(jobKey);
                    CronTrigger cronTrigger = (CronTrigger) triggers.get(0);
                    cronJobResp.setNextFireTime(cronTrigger.getNextFireTime());
                    cronJobResp.setPreFireTime(cronTrigger.getPreviousFireTime());
                    cronJobResp.setCronExpression(cronTrigger.getCronExpression());
                    cronJobResp.setDescription(cronTrigger.getDescription());
                    Trigger.TriggerState triggerState = scheduler.getTriggerState(cronTrigger.getKey());
                    cronJobResp.setState(triggerState.name());

                    cronJobDtoList.add(cronJobResp);
                }

            }
        } catch (SchedulerException e) {
            log.error("查看定时任务失败:" + e);
            throw new ApplicationException(ResultCode.SCHEDULE_DISPATCH_ERROR,"创建定时任务失败:调度异常");
        }
        log.info("查看定时任务结束");
        return R.ok("查询成功",cronJobDtoList);
    }
}
